/* do not edit automatically generated by mc from alists.  */
/* alists.mod address lists module.

Copyright (C) 2015-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius@glam.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#   include "GStorage.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _alists_H
#define _alists_C

#   include "GStorage.h"

typedef struct alists_performOperation_p alists_performOperation;

#   define MaxnoOfelements 5
typedef struct alists__T1_r alists__T1;

typedef struct alists__T2_a alists__T2;

typedef alists__T1 *alists_alist;

typedef void (*alists_performOperation_t) (void *);
struct alists_performOperation_p { alists_performOperation_t proc; };

struct alists__T2_a { void * array[MaxnoOfelements-1+1]; };
struct alists__T1_r {
                      unsigned int noOfelements;
                      alists__T2 elements;
                      alists_alist next;
                    };


/*
   initList - creates a new alist, l.
*/

extern "C" alists_alist alists_initList (void);

/*
   killList - deletes the complete alist, l.
*/

extern "C" void alists_killList (alists_alist *l);

/*
   putItemIntoList - places an ADDRESS, c, into alist, l.
*/

extern "C" void alists_putItemIntoList (alists_alist l, void * c);

/*
   getItemFromList - retrieves the nth WORD from alist, l.
*/

extern "C" void * alists_getItemFromList (alists_alist l, unsigned int n);

/*
   getIndexOfList - returns the index for WORD, c, in alist, l.
                    If more than one WORD, c, exists the index
                    for the first is returned.
*/

extern "C" unsigned int alists_getIndexOfList (alists_alist l, void * c);

/*
   noOfItemsInList - returns the number of items in alist, l.
*/

extern "C" unsigned int alists_noOfItemsInList (alists_alist l);

/*
   includeItemIntoList - adds an ADDRESS, c, into a alist providing
                         the value does not already exist.
*/

extern "C" void alists_includeItemIntoList (alists_alist l, void * c);

/*
   removeItemFromList - removes a ADDRESS, c, from a alist.
                        It assumes that this value only appears once.
*/

extern "C" void alists_removeItemFromList (alists_alist l, void * c);

/*
   isItemInList - returns true if a ADDRESS, c, was found in alist, l.
*/

extern "C" bool alists_isItemInList (alists_alist l, void * c);

/*
   foreachItemInListDo - calls procedure, P, foreach item in alist, l.
*/

extern "C" void alists_foreachItemInListDo (alists_alist l, alists_performOperation p);

/*
   duplicateList - returns a duplicate alist derived from, l.
*/

extern "C" alists_alist alists_duplicateList (alists_alist l);

/*
   removeItem - remove an element at index, i, from the alist data type.
*/

static void removeItem (alists_alist p, alists_alist l, unsigned int i);


/*
   removeItem - remove an element at index, i, from the alist data type.
*/

static void removeItem (alists_alist p, alists_alist l, unsigned int i)
{
  l->noOfelements -= 1;
  while (i <= l->noOfelements)
    {
      l->elements.array[i-1] = l->elements.array[i+1-1];
      i += 1;
    }
  if ((l->noOfelements == 0) && (p != NULL))
    {
      p->next = l->next;
      Storage_DEALLOCATE ((void **) &l, sizeof (alists__T1));
    }
}


/*
   initList - creates a new alist, l.
*/

extern "C" alists_alist alists_initList (void)
{
  alists_alist l;

  Storage_ALLOCATE ((void **) &l, sizeof (alists__T1));
  l->noOfelements = 0;
  l->next = NULL;
  return l;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   killList - deletes the complete alist, l.
*/

extern "C" void alists_killList (alists_alist *l)
{
  if ((*l) != NULL)
    {
      if ((*l)->next != NULL)
        {
          alists_killList (&(*l)->next);
        }
      Storage_DEALLOCATE ((void **) &(*l), sizeof (alists__T1));
    }
}


/*
   putItemIntoList - places an ADDRESS, c, into alist, l.
*/

extern "C" void alists_putItemIntoList (alists_alist l, void * c)
{
  if (l->noOfelements < MaxnoOfelements)
    {
      l->noOfelements += 1;
      l->elements.array[l->noOfelements-1] = c;
    }
  else if (l->next != NULL)
    {
      /* avoid dangling else.  */
      alists_putItemIntoList (l->next, c);
    }
  else
    {
      /* avoid dangling else.  */
      l->next = alists_initList ();
      alists_putItemIntoList (l->next, c);
    }
}


/*
   getItemFromList - retrieves the nth WORD from alist, l.
*/

extern "C" void * alists_getItemFromList (alists_alist l, unsigned int n)
{
  while (l != NULL)
    {
      if (n <= l->noOfelements)
        {
          return l->elements.array[n-1];
        }
      else
        {
          n -= l->noOfelements;
        }
      l = l->next;
    }
  return reinterpret_cast<void *> (0);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   getIndexOfList - returns the index for WORD, c, in alist, l.
                    If more than one WORD, c, exists the index
                    for the first is returned.
*/

extern "C" unsigned int alists_getIndexOfList (alists_alist l, void * c)
{
  unsigned int i;

  if (l == NULL)
    {
      return 0;
    }
  else
    {
      i = 1;
      while (i <= l->noOfelements)
        {
          if (l->elements.array[i-1] == c)
            {
              return i;
            }
          else
            {
              i += 1;
            }
        }
      return l->noOfelements+(alists_getIndexOfList (l->next, c));
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   noOfItemsInList - returns the number of items in alist, l.
*/

extern "C" unsigned int alists_noOfItemsInList (alists_alist l)
{
  unsigned int t;

  if (l == NULL)
    {
      return 0;
    }
  else
    {
      t = 0;
      do {
        t += l->noOfelements;
        l = l->next;
      } while (! (l == NULL));
      return t;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   includeItemIntoList - adds an ADDRESS, c, into a alist providing
                         the value does not already exist.
*/

extern "C" void alists_includeItemIntoList (alists_alist l, void * c)
{
  if (! (alists_isItemInList (l, c)))
    {
      alists_putItemIntoList (l, c);
    }
}


/*
   removeItemFromList - removes a ADDRESS, c, from a alist.
                        It assumes that this value only appears once.
*/

extern "C" void alists_removeItemFromList (alists_alist l, void * c)
{
  alists_alist p;
  unsigned int i;
  bool found;

  if (l != NULL)
    {
      found = false;
      p = NULL;
      do {
        i = 1;
        while ((i <= l->noOfelements) && (l->elements.array[i-1] != c))
          {
            i += 1;
          }
        if ((i <= l->noOfelements) && (l->elements.array[i-1] == c))
          {
            found = true;
          }
        else
          {
            p = l;
            l = l->next;
          }
      } while (! ((l == NULL) || found));
      if (found)
        {
          removeItem (p, l, i);
        }
    }
}


/*
   isItemInList - returns true if a ADDRESS, c, was found in alist, l.
*/

extern "C" bool alists_isItemInList (alists_alist l, void * c)
{
  unsigned int i;

  do {
    i = 1;
    while (i <= l->noOfelements)
      {
        if (l->elements.array[i-1] == c)
          {
            return true;
          }
        else
          {
            i += 1;
          }
      }
    l = l->next;
  } while (! (l == NULL));
  return false;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   foreachItemInListDo - calls procedure, P, foreach item in alist, l.
*/

extern "C" void alists_foreachItemInListDo (alists_alist l, alists_performOperation p)
{
  unsigned int i;
  unsigned int n;

  n = alists_noOfItemsInList (l);
  i = 1;
  while (i <= n)
    {
      (*p.proc) (alists_getItemFromList (l, i));
      i += 1;
    }
}


/*
   duplicateList - returns a duplicate alist derived from, l.
*/

extern "C" alists_alist alists_duplicateList (alists_alist l)
{
  alists_alist m;
  unsigned int n;
  unsigned int i;

  m = alists_initList ();
  n = alists_noOfItemsInList (l);
  i = 1;
  while (i <= n)
    {
      alists_putItemIntoList (m, alists_getItemFromList (l, i));
      i += 1;
    }
  return m;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void _M2_alists_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}

extern "C" void _M2_alists_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}
